package com.ken.ability.gateway.routes;

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * 基于Nacos的动态路由配置
 *
 */
/* - json格式
[
  {
    "id": "DEMO_API_ROUTE",
    "order": 1,
    "uri": "lb://demo-api",
    "predicates": [
      {
        "args": {
          "_genkey_0": "/demoApi/**"
        },
        "name": "Path"
      }
    ],
    "filters": [
      {
        "args": {
          "name": "hystrix",
          "fallbackUri": "forward:/hystrix"
        },
        "name": "Hystrix"
      },
      {
        "args": {},
        "name": "RateLimit"
      }
    ]
  }
]
 */
@Slf4j
public class NacosDynamicRouteDefinitionRepository implements RouteDefinitionRepository, ApplicationEventPublisherAware{

    private static final String DATA_ID = "gateway-routes.json";
    private static final String GROUP_ID = "gateway-group";

    /**
     * 动态路由的路由规则集合
     */
    private List<RouteDefinition> routeDefinitions;

    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private NacosConfigManager configServiceManager;
    private ConfigService configService;

    @PostConstruct
    public void init(){
        configService = this.configServiceManager.getConfigService();
        String configInfo = null;
        try {
            configInfo = configService.getConfigAndSignListener(DATA_ID, GROUP_ID, 1000, new AbstractListener() {
                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.debug("[Dynamic_Route] - nacos监听获取到动态路由配置信息 - {}", configInfo);
                    if (configInfo != null) {
                        routeDefinitions = JSONArray.parseArray(configInfo, RouteDefinition.class);
                        //手动刷新路由配置
                        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(NacosDynamicRouteDefinitionRepository.this));
                    }
                }
            });
            log.debug("[Dynamic_Route] - 从nacos获取到动态路由配置信息 - {}", configInfo);
            if (configInfo != null) {
                routeDefinitions = JSONArray.parseArray(configInfo, RouteDefinition.class);
            }
        } catch (NacosException e) {
            log.error("[Dynamic_Route] - 获取nacos的动态路由配置异常", e);
        }
    }

    /**
     * 返回当前的路由规则
     * @return
     */
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
//        log.debug("[Dynamic_Route] - 加载动态路由 - {}", JSON.toJSONString(routeDefinitions));
        if (CollectionUtils.isEmpty(routeDefinitions))
            return Flux.empty();
        return Flux.fromIterable(routeDefinitions);
    }
    

    /**
     * 将配置信息转换成配置集合
     * @return
     */
//    private List<RouteDefinition> json2Routes(String configInfo){
//        try {
//            JSONArray routeDefinitonJsons = JSON.parseArray(configInfo);
//            //路由对象集合
//            List<RouteDefinition> routeDefinitions = new ArrayList<>();
//            for (int i = 0; i < routeDefinitonJsons.size(); i++) {
//                //获得单个路由对象
//                JSONObject routeDefinitonJson = routeDefinitonJsons.getJSONObject(i);
//
//                //创建对象
//                RouteDefinition routeDefinition = new RouteDefinition();
//                String id = routeDefinitonJson.getString("id");
//                //设置id
//                if (!StringUtils.isEmpty(id))
//                    routeDefinition.setId(id);
//                //设置uri
//                String uri = routeDefinitonJson.getString("uri");
//                if (!StringUtils.isEmpty(uri))
//                    routeDefinition.setUri(URI.create(uri));
//                //设置predicates
//                List<PredicateDefinition> predicateDefinitions = new ArrayList<>();
//
//                JSONArray predicates = routeDefinitonJson.getJSONArray("predicates");
//                for (int j = 0; j < predicates.size(); j++) {
//                    String predicateString = predicates.getString(j);
//                    PredicateDefinition predicateDefinition = new PredicateDefinition(predicateString);
//                    predicateDefinitions.add(predicateDefinition);
//                }
//                routeDefinition.setPredicates(predicateDefinitions);
//
//                //设置Filters
//                List<FilterDefinition> filterDefinitions = new ArrayList<>();
//
//                JSONArray filters = routeDefinitonJson.getJSONArray("filters");
//                for (int k = 0; k < filters.size(); k++) {
//                    JSONObject filterJSON = filters.getJSONObject(k);
//                    String name = filterJSON.getString("name");
//                    //过滤器对象
//                    FilterDefinition filterDefinition = new FilterDefinition();
//                    filterDefinition.setName(name);
//
//                    //处理参数
//                    filterDefinitions.add(filterDefinition);
//                }
//                routeDefinition.setFilters(filterDefinitions);
//            }
//        } catch (Exception e) {
//            log.error("[Dynamic_Route] - 解析nacos动态路由配置数据异常 - {}", configInfo, e);
//        }
//
//        return null;
//    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        log.debug("[Dynamic_Route] - nacos动态路由的save方法被执行 - {}", route);
        return Mono.empty();
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        log.debug("[Dynamic_Route] - nacos动态路由的delete方法被执行 - {}", routeId);
        return Mono.empty();
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
